//---------------------------------------------------------------------------

#include "vcl_stl.h"
#pragma hdrstop

#include "h_base.h"
#include "h_xml.h"
using namespace h_base;
using namespace h_xml;

#include "h_global.h"

//---------------------------------------------------------------------------

void __fastcall HComm::Init(void)
{
   WSADATA WSAData;

   WSAStartup(0x0202, &WSAData);
}

void __fastcall HComm::Close(void)
{
   WSACleanup();
}

int __fastcall HComm::Accept(SOCKET Sock, SOCKET &MsgSock,
   string &IpAddr, int TimeOut, DWORD *ErrCode,
   const HANDLE *EventHandles, int NumOfEvent)
{
   int i, r;
   sockaddr_in Addr;
   WSANETWORKEVENTS WSANetworkEvents;
   auto_ptr<TSimpleEvent> SocketEvent(new TSimpleEvent(false));
   HANDLE Events[8];
   DWORD LastError;

   if( NumOfEvent >= 8 )
   {
      LastError = 0;
      r = -3;
      goto finish;
   }

   if( TimeOut != INFINITE )
      TimeOut *= 1000;

   Events[0] = reinterpret_cast<HANDLE>(SocketEvent->Handle);

   for( i = 0; i < NumOfEvent; i++ )
      Events[i + 1] = EventHandles[i];

   NumOfEvent++;

   ResetEvent(Events[0]);

   if( WSAEventSelect(Sock, Events[0], FD_ACCEPT) != 0 )
   {
      LastError = WSAGetLastError();
      r = -1;
      goto finish;
   }

   r = sizeof(Addr);
   MsgSock = accept(Sock, reinterpret_cast<sockaddr*>(&Addr), &r);

   if( MsgSock == INVALID_SOCKET )
   {
      LastError = WSAGetLastError();
      if( LastError != WSAEWOULDBLOCK )
      {
         r = -1;
         goto finish;
      }
      for(;;)
      {
         r = WaitForMultipleObjects(NumOfEvent, Events, false, TimeOut);
         if( r == WAIT_OBJECT_0 )
         {
            if( WSAEnumNetworkEvents(Sock, Events[0], &WSANetworkEvents) != 0 )
            {
               LastError = WSAGetLastError();
               r = -1;
               goto finish;
            }
            if( WSANetworkEvents.lNetworkEvents & FD_ACCEPT )
            {
               if( WSANetworkEvents.iErrorCode[FD_ACCEPT_BIT] == 0 )
               {
                  r = sizeof(Addr);
                  MsgSock = accept(Sock,
                     reinterpret_cast<sockaddr*>(&Addr), &r);
                  if( MsgSock == INVALID_SOCKET )
                  {
                     LastError = WSAGetLastError();
                     r = -1;
                     goto finish;
                  }
                  IpAddr = inet_ntoa(Addr.sin_addr);
                  LastError = 0;
                  r = 0;
                  goto finish;
               }
               else
               {
                  LastError = WSANetworkEvents.iErrorCode[FD_ACCEPT_BIT];
                  r = -1;
                  goto finish;
               }
            }
            else
               continue;
         }
         else if( r > WAIT_OBJECT_0 && r < WAIT_OBJECT_0 + NumOfEvent )
         {
            LastError = 0;
            r = r - WAIT_OBJECT_0;
            goto finish;
         }
         else if( r == WAIT_TIMEOUT )
         {
            LastError = 0;
            r = -2;
            goto finish;
         }
         else
         {
            LastError = GetLastError();
            r = -1;
            goto finish;
         }
      }
   }

   LastError = 0;
   r = 0;

finish :

   if( ErrCode != NULL )
      *ErrCode = LastError;

   return r;
}

int __fastcall HComm::Connect(SOCKET Sock, const char *IpAddr,
   int Port, int TimeOut, DWORD *ErrCode,
   const HANDLE *EventHandles, int NumOfEvent)
{
   int i, r;
   sockaddr_in Addr;
   WSANETWORKEVENTS WSANetworkEvents;
   auto_ptr<TSimpleEvent> SocketEvent(new TSimpleEvent(false));
   HANDLE Events[8];
   DWORD LastError;

   if( NumOfEvent >= 8 )
   {
      LastError = 0;
      r = -3;
      goto finish;
   }

   if( TimeOut != INFINITE )
      TimeOut *= 1000;

   Events[0] = reinterpret_cast<HANDLE>(SocketEvent->Handle);

   for( i = 0; i < NumOfEvent; i++ )
      Events[i + 1] = EventHandles[i];

   NumOfEvent++;

   ResetEvent(Events[0]);

   Addr.sin_family = PF_INET;
   Addr.sin_addr.s_addr = inet_addr(IpAddr);
   Addr.sin_port = htons(Port);

   if( WSAEventSelect(Sock, Events[0], FD_CONNECT) != 0 )
   {
      LastError = WSAGetLastError();
      r = -1;
      goto finish;
   }

   if( connect(Sock, reinterpret_cast<sockaddr*>(&Addr),
          sizeof(Addr)) == SOCKET_ERROR )
   {
      LastError = WSAGetLastError();
      if( LastError != WSAEWOULDBLOCK )
      {
         r = -1;
         goto finish;
      }
      for(;;)
      {
         r = WaitForMultipleObjects(NumOfEvent, Events, false, TimeOut);
         if( r == WAIT_OBJECT_0 )
         {
            if( WSAEnumNetworkEvents(Sock, Events[0], &WSANetworkEvents) != 0 )
            {
               LastError = WSAGetLastError();
               r = -1;
               goto finish;
            }
            if( WSANetworkEvents.lNetworkEvents & FD_CONNECT )
            {
               if( WSANetworkEvents.iErrorCode[FD_CONNECT_BIT] == 0 )
               {
                  LastError = 0;
                  r = 0;
                  goto finish;
               }
               else
               {
                  LastError = WSANetworkEvents.iErrorCode[FD_CONNECT_BIT];
                  r = -1;
                  goto finish;
               }
            }
            else
               continue;
         }
         else if( r > WAIT_OBJECT_0 && r < WAIT_OBJECT_0 + NumOfEvent )
         {
            LastError = 0;
            r = r - WAIT_OBJECT_0;
            goto finish;
         }
         else if( r == WAIT_TIMEOUT )
         {
            LastError = 0;
            r = -2;
            goto finish;
         }
         else
         {
            LastError = GetLastError();
            r = -1;
            goto finish;
         }
      }
   }

   LastError = 0;
   r = 0;

finish :

   if( ErrCode != NULL )
      *ErrCode = LastError;

   return r;
}

int __fastcall HComm::Read(SOCKET Sock, void *Buf, int Len,
   int TimeOut, DWORD *ErrCode,
   const HANDLE *EventHandles, int NumOfEvent)
{
   int r, i;
   char *s;
   WSANETWORKEVENTS WSANetworkEvents;
   auto_ptr<TSimpleEvent> SocketEvent(new TSimpleEvent(false));
   HANDLE Events[8];
   DWORD LastError;

   if( Len == 0 )
      return 0;

   if( NumOfEvent >= 8 )
   {
      LastError = 0;
      r = -3;
      goto finish;
   }

   if( TimeOut != INFINITE )
      TimeOut *= 1000;

   Events[0] = reinterpret_cast<HANDLE>(SocketEvent->Handle);

   for( i = 0; i < NumOfEvent; i++ )
      Events[i + 1] = EventHandles[i];

   NumOfEvent++;

   if( WSAEventSelect(Sock, Events[0], FD_READ | FD_CLOSE) != 0 )
   {
      LastError = WSAGetLastError();
      r = -1;
      goto finish;
   }

   for( s = static_cast<char*>(Buf), i = 0; i < Len;)
   {
      ResetEvent(Events[0]);
      r = recv(Sock, s + i, Len - i, 0);
      if( r == 0 )
         return -4;
      if( r == SOCKET_ERROR )
      {
         LastError = WSAGetLastError();
         if( LastError != WSAEWOULDBLOCK )
         {
            r = -1;
            goto finish;
         }
         r = WaitForMultipleObjects(NumOfEvent, Events, false, TimeOut);
         if( r == WAIT_OBJECT_0 )
         {
            if( WSAEnumNetworkEvents(Sock, Events[0], &WSANetworkEvents) != 0 )
            {
               LastError = WSAGetLastError();
               r = -1;
               goto finish;
            }
            if( WSANetworkEvents.lNetworkEvents & FD_READ )
            {
               if( WSANetworkEvents.iErrorCode[FD_READ_BIT] == 0 )
               {
                  r = recv(Sock, s + i, Len - i, 0);
                  if( r == SOCKET_ERROR )
                  {
                     LastError = WSAGetLastError();
                     r = -1;
                     goto finish;
                  }
               }
               else
               {
                  LastError = WSANetworkEvents.iErrorCode[FD_READ_BIT];
                  r = -1;
                  goto finish;
               }
            }
            else if( WSANetworkEvents.lNetworkEvents & FD_CLOSE )
            {
               if( WSANetworkEvents.iErrorCode[FD_CLOSE_BIT] == 0 )
               {
                  LastError = 0;
                  r = -4;
                  goto finish;
               }
               else
               {
                  LastError = WSANetworkEvents.iErrorCode[FD_CLOSE_BIT];
                  r = -1;
                  goto finish;
               }
            }
            else
               continue;
         }
         else if( r > WAIT_OBJECT_0 && r < WAIT_OBJECT_0 + NumOfEvent )
         {
            LastError = 0;
            r = r - WAIT_OBJECT_0;
            goto finish;
         }
         else if( r == WAIT_TIMEOUT )
         {
            LastError = 0;
            r = -2;
            goto finish;
         }
         else
         {
            LastError = GetLastError();
            r = -1;
            goto finish;
         }
      }
      i += r;
   }

   LastError = 0;
   r = 0;

finish :

   if( ErrCode != NULL )
      *ErrCode = LastError;

   return r;
}

int __fastcall HComm::Write(SOCKET Sock, const void *Buf, int Len,
   int TimeOut, DWORD *ErrCode,
   const HANDLE *EventHandles, int NumOfEvent)
{
   int r, i;
   const char *s;
   WSANETWORKEVENTS WSANetworkEvents;
   auto_ptr<TSimpleEvent> SocketEvent(new TSimpleEvent(false));
   HANDLE Events[8];
   DWORD LastError;

   if( Len == 0 )
      return 0;

   if( NumOfEvent >= 8 )
   {
      LastError = 0;
      r = -3;
      goto finish;
   }

   if( TimeOut != INFINITE )
      TimeOut *= 1000;

   Events[0] = reinterpret_cast<HANDLE>(SocketEvent->Handle);

   for( i = 0; i < NumOfEvent; i++ )
      Events[i + 1] = EventHandles[i];

   NumOfEvent++;

   if( WSAEventSelect(Sock, Events[0], FD_WRITE | FD_CLOSE) != 0 )
   {
      LastError = WSAGetLastError();
      r = -1;
      goto finish;
   }

   for( s = static_cast<const char*>(Buf), i = 0; i < Len; )
   {
      ResetEvent(Events[0]);
      r = send(Sock, s + i, Len - i, 0);
      if( r == SOCKET_ERROR )
      {
         LastError = WSAGetLastError();
         if( LastError != WSAEWOULDBLOCK )
         {
            r = -1;
            goto finish;
         }
         r = WaitForMultipleObjects(NumOfEvent, Events, false, TimeOut);
         if( r == WAIT_OBJECT_0 )
         {
            if( WSAEnumNetworkEvents(Sock, Events[0], &WSANetworkEvents) != 0 )
            {
               LastError = WSAGetLastError();
               r = -1;
               goto finish;
            }
            if( WSANetworkEvents.lNetworkEvents & FD_WRITE )
            {
               if( WSANetworkEvents.iErrorCode[FD_WRITE_BIT] == 0 )
               {
                  r = send(Sock, s + i, Len - i, 0);
                  if( r == SOCKET_ERROR )
                  {
                     LastError = WSAGetLastError();
                     r = -1;
                     goto finish;
                  }
               }
               else
               {
                  LastError = WSANetworkEvents.iErrorCode[FD_WRITE_BIT];
                  r = -1;
                  goto finish;
               }
            }
            else
            {
               if( WSANetworkEvents.iErrorCode[FD_CLOSE_BIT] == 0 )
               {
                  LastError = 0;
                  r = -4;
                  goto finish;
               }
               else
               {
                  LastError = WSANetworkEvents.iErrorCode[FD_CLOSE_BIT];
                  r = -1;
                  goto finish;
               }
            }
         }
         else if( r > WAIT_OBJECT_0 && r < WAIT_OBJECT_0 + NumOfEvent )
         {
            LastError = 0;
            r = r - WAIT_OBJECT_0;
            goto finish;
         }
         else if( r == WAIT_TIMEOUT )
         {
            LastError = 0;
            r = -2;
            goto finish;
         }
         else
         {
            LastError = GetLastError();
            r = -1;
            goto finish;
         }
      }
      i += r;
   }

   LastError = 0;
   r = 0;

finish :

   if( ErrCode != NULL )
      *ErrCode = LastError;

   return r;
}

int __fastcall HComm::ReadByLength(SOCKET Sock, void *Buf, int &Len,
   int TimeOut, DWORD *ErrCode, const HANDLE *EventHandles, int NumOfEvent)
{
   int r;
   char LenBuf[8 + 1];

   r = Read(Sock, LenBuf, 8, TimeOut, ErrCode, EventHandles, NumOfEvent);

   if( r != 0 )
      return r;

   LenBuf[8] = '\0';
   Len = HexStrToInt(LenBuf);
   return Read(Sock, Buf, Len, TimeOut, ErrCode, EventHandles, NumOfEvent);
}

int __fastcall HComm::WriteByLength(SOCKET Sock, const void *Buf, int Len,
   int TimeOut, DWORD *ErrCode, const HANDLE *EventHandles, int NumOfEvent)
{
   int r;
   char LenBuf[80 + 1];

   snprintf(LenBuf, 80, "%08x", Len);
   r = Write(Sock, LenBuf, 8, TimeOut, ErrCode, EventHandles, NumOfEvent);

   if( r != 0 )
      return r;

   return Write(Sock, Buf, Len, TimeOut, ErrCode, EventHandles, NumOfEvent);
}

bool __fastcall CheckExpr(const UTF8String &Expr, UTF8String &ErrorString)
{
   vector<string> Vec;

   h_base::SplitString(Expr.c_str(), '\n', Vec);

   if( Vec.size() <= 1 )
      return true;

   if( Vec[0] != "{" || Vec[Vec.size() - 1] != "}" )
   {
      ErrorString = "'{' missing?";
      return false;
   }

   return true;
}

void __fastcall SetStringToMemo(TMemo *Memo, const UTF8String &String)
{
   vector<string> Vec;

   h_base::SplitString(String.c_str(), '\n', Vec);
   Memo->Lines->Clear();

   if( String == "" )
      return;

   for( int i = 0; i < Vec.size(); i++ )
      Memo->Lines->Add(UTF8String(Vec[i].c_str()));
}

UTF8String __fastcall GetStringFromMemo(TMemo *Memo)
{
   int i, j;
   UTF8String Result;

   for( j = Memo->Lines->Count; j > 0; j-- )
   {
      if( Memo->Lines->Strings[j - 1].TrimRight() != "" )
         break;
   }

   for( i = 0; i < j; i++ )
   {
      if( Result != "" )
         Result += "\n";
      Result += Memo->Lines->Strings[i].TrimRight();
   }

   return Result;
}

bool __fastcall FileExist(const UTF8String &FileName)
{
   return FileExists(FileName);
}

#define FONT_STYLE_BOLD        0x0001
#define FONT_STYLE_ITALIC      0x0002
#define FONT_STYLE_UNDERLINE   0x0004
#define FONT_STYLE_STRIKE_OUT  0x0008

void __fastcall IntToFontStyle(int Int,
   Set<TFontStyle, fsBold, fsStrikeOut> &Style)
{
   Style.Clear();

   if ( Int & FONT_STYLE_BOLD )
   {
      Style << fsBold;
   }


   if ( Int & FONT_STYLE_ITALIC )
   {
      Style << fsItalic;
   }

   if ( Int & FONT_STYLE_UNDERLINE )
   {
      Style << fsUnderline;
   }

   if ( Int & FONT_STYLE_STRIKE_OUT )
   {
      Style << fsStrikeOut;
   }
}

void __fastcall FontStyleToInt(int &Int,
   const Set<TFontStyle, fsBold, fsStrikeOut> &Style)
{
   Int = 0;

   if ( Style.Contains(fsBold) )
   {
      Int |= FONT_STYLE_BOLD;
   }

   if ( Style.Contains(fsItalic) )
   {
      Int |= FONT_STYLE_ITALIC;
   }

   if ( Style.Contains(fsUnderline) )
   {
      Int |= FONT_STYLE_UNDERLINE;
   }

   if ( Style.Contains(fsStrikeOut) )
   {
      Int |= FONT_STYLE_STRIKE_OUT;
   }
}

UTF8String __fastcall GetDateTime(const char *s)
{
   char Str[8 + 6 + 1];

   memset(Str, '0', 8 + 6);
   Str[8 + 6] = '\0';

   for ( int i = 0; i < 8 + 6 && *s != '\0'; s++ )
   {
      if ( isdigit(*s) )
      {
         Str[i++] = *s;
      }
   }

   return UTF8String(Str);
}

UTF8String __fastcall DiffTime(const UTF8String &StartTime,
   const UTF8String &EndTime, int SubDelta)
{
   UTF8String Result;

   if ( StartTime.TrimRight() == "" || EndTime.TrimRight() == "" )
   {
      return "";
   }

   unsigned short Year, Month, Day;
   unsigned short Hour, Min, Sec, MSec;

   Year = StrToInt(EndTime.SubString(1, 4).c_str());
   Month = StrToInt(EndTime.SubString(1 + 4, 2).c_str());
   Day = StrToInt(EndTime.SubString(1 + 4 + 2, 2).c_str());
   Hour = StrToInt(EndTime.SubString(1 + 4 + 2 + 2, 2).c_str());
   Min = StrToInt(EndTime.SubString(1 + 4 + 2 + 2 + 2, 2).c_str());
   Sec = StrToInt(EndTime.SubString(1 + 4 + 2 + 2 + 2 + 2, 2).c_str());

   TDateTime EndDateTime = TDateTime(Year, Month, Day) +
      TDateTime(Hour, Min, Sec, 0);

   Year = StrToInt(StartTime.SubString(1, 4).c_str());
   Month = StrToInt(StartTime.SubString(1 + 4, 2).c_str());
   Day = StrToInt(StartTime.SubString(1 + 4 + 2, 2).c_str());
   Hour = StrToInt(StartTime.SubString(1 + 4 + 2 + 2, 2).c_str());
   Min = StrToInt(StartTime.SubString(1 + 4 + 2 + 2 + 2, 2).c_str());
   Sec = StrToInt(StartTime.SubString(1 + 4 + 2 + 2 + 2 + 2, 2).c_str());

   TDateTime StartDateTime = TDateTime(Year, Month, Day) +
      TDateTime(Hour, Min, Sec, 0);

   int Delta = DateTimeToSec(EndDateTime - StartDateTime) - SubDelta;

   Result.sprintf("%02d:%02d:%02d", Delta / 3600, Delta % 3600 / 60, Delta % 60);
   return Result;
}

void __fastcall DiffTime(const UTF8String &StartTime,
   const UTF8String &EndTime, unsigned short &Hour, unsigned short &Min,
   unsigned short &Sec)
{
   UTF8String Result;

   if ( StartTime.TrimRight() == "" || EndTime.TrimRight() == "" )
   {
      Hour = 0;
      Min = 0;
      Sec = 0;
      return;
   }

   unsigned short Year, Month, Day;
   unsigned short MSec;

   Year = StrToInt(EndTime.SubString(1, 4).c_str());
   Month = StrToInt(EndTime.SubString(1 + 4, 2).c_str());
   Day = StrToInt(EndTime.SubString(1 + 4 + 2, 2).c_str());
   Hour = StrToInt(EndTime.SubString(1 + 4 + 2 + 2, 2).c_str());
   Min = StrToInt(EndTime.SubString(1 + 4 + 2 + 2 + 2, 2).c_str());
   Sec = StrToInt(EndTime.SubString(1 + 4 + 2 + 2 + 2 + 2, 2).c_str());

   TDateTime EndDateTime = TDateTime(Year, Month, Day) +
      TDateTime(Hour, Min, Sec, 0);

   Year = StrToInt(StartTime.SubString(1, 4).c_str());
   Month = StrToInt(StartTime.SubString(1 + 4, 2).c_str());
   Day = StrToInt(StartTime.SubString(1 + 4 + 2, 2).c_str());
   Hour = StrToInt(StartTime.SubString(1 + 4 + 2 + 2, 2).c_str());
   Min = StrToInt(StartTime.SubString(1 + 4 + 2 + 2 + 2, 2).c_str());
   Sec = StrToInt(StartTime.SubString(1 + 4 + 2 + 2 + 2 + 2, 2).c_str());

   TDateTime StartDateTime = TDateTime(Year, Month, Day) +
      TDateTime(Hour, Min, Sec, 0);

   int Delta = DateTimeToSec(EndDateTime - StartDateTime);

   Hour = Delta / 3600;
   Min = Delta % 3600 / 60;
   Sec = Delta % 60;
}

void __fastcall DiffTime(const TDateTime &StartTime,
   const TDateTime &EndTime, unsigned short &Hour, unsigned short &Min,
   unsigned short &Sec)
{
   int Delta = DateTimeToSec(EndTime - StartTime);

   Hour = Delta / 3600;
   Min = Delta % 3600 / 60;
   Sec = Delta % 60;
}

int __fastcall DiffTimeSec(const UTF8String &StartTime,
   const UTF8String &EndTime)
{
   unsigned short Hour;
   unsigned short Min;
   unsigned short Sec;

   DiffTime(StartTime, EndTime, Hour, Min, Sec);
   return Hour * 3600 + Min * 60 + Sec;
}

UTF8String __fastcall FormatDateTime(const UTF8String &DateTime)
{
   if ( DateTime.TrimRight() == "" )
   {
      return "";
   }

   UTF8String Result;

   Result.sprintf("%.4s/%.2s/%.2s  %.2s:%.2s:%.2s",
      DateTime.c_str(),
      DateTime.c_str() + 4,
      DateTime.c_str() + 4 + 2,
      DateTime.c_str() + 4 + 2 + 2,
      DateTime.c_str() + 4 + 2 + 2 + 2,
      DateTime.c_str() + 4 + 2 + 2 + 2 + 2);

   return Result;
}

bool __fastcall PosInRect(int XPos, int YPos, const TRect &Rect)
{
   return XPos >= Rect.Left && XPos < Rect.Right &&
      YPos >= Rect.Top && YPos < Rect.Bottom;
}

int __fastcall StatusToInt(const UTF8String &Status)
{
   const char *s = Status.c_str();

   if ( *s == 'U' )
      return 0;

   if ( *s == 'F' )
      return 1;

   if ( *s == 'R' )
      return 2;

   if ( *s == 'S' )
   {
      if ( s[1] == 'K' )
         return 3;
      else
         return 4;
   }

   return 5;
}

bool __fastcall ToDateTime(const UTF8String &Str, TDateTime &DateTime)
{
   const char *s = Str.c_str();
   int Year;
   int Month;
   int Day;
   int Hour;
   int Min;
   int Sec;
   char TmpStr[80 + 1];
   int Pos = 0;

   Pos += ReadWord(s + Pos, TmpStr, " /:", 80);
   Year = StrToInt(TmpStr);
   Pos += ReadWord(s + Pos, TmpStr, " /:", 80);

   if ( strcmp(TmpStr, "/") != 0 )
   {
      return false;
   }

   Pos += ReadWord(s + Pos, TmpStr, " /:", 80);
   Month = StrToInt(TmpStr);
   Pos += ReadWord(s + Pos, TmpStr, " /:", 80);

   if ( strcmp(TmpStr, "/") != 0 )
   {
      return false;
   }

   Pos += ReadWord(s + Pos, TmpStr, " /:", 80);
   Day = StrToInt(TmpStr);
   Pos += ReadWord(s + Pos, TmpStr, " /:", 80);
   Hour = StrToInt(TmpStr);
   Pos += ReadWord(s + Pos, TmpStr, " /:", 80);

   if ( strcmp(TmpStr, ":") != 0 )
   {
      return false;
   }

   Pos += ReadWord(s + Pos, TmpStr, " /:", 80);
   Min = StrToInt(TmpStr);
   Pos += ReadWord(s + Pos, TmpStr, " /:", 80);

   if ( strcmp(TmpStr, ":") != 0 )
   {
      return false;
   }

   Pos += ReadWord(s + Pos, TmpStr, " /:", 80);
   Sec = StrToInt(TmpStr);

   if ( Year < 1900 || Year > 3000 || Month < 1 || Month > 12 ||
        Day < 1 || Day > 31 || Hour < 0 || Hour > 23 ||
        Min < 0 || Min > 59 || Sec < 0 || Sec > 59 )
   {
      return false;
   }

   DateTime = TDateTime(Year, Month, Day) + TDateTime(Hour, Min, Sec, 0);
   return true;
}

int __fastcall DateTimeToSec(const TDateTime &DateTime)
{
   unsigned short Hour;
   unsigned short Min;
   unsigned short Sec;
   unsigned short MSec;

   DateTime.DecodeTime(&Hour, &Min, &Sec, &MSec);
   return (int)DateTime * 60 * 60 * 24 + Hour * 60 * 60 + Min * 60 + Sec;
}

TDateTime __fastcall SecToDateTime(int Sec)
{
   int Day = Sec / ( 60 * 60 * 24 );

   Sec %= 60 * 60 * 24;

   return TDateTime(Day) + TDateTime(Sec / 3600, Sec % 3600 / 60, Sec % 60, 0);
}

void __fastcall CreateSpecialDateList(TComboBox *ComboBox,
   const vector<string> &Dates)
{
   ComboBox->Items->Clear();
   ComboBox->Items->Add("");

   for ( int i = 0; i < Dates.size(); i++ )
   {
      ComboBox->Items->Add(UTF8String(Dates[i].c_str()));
   }
}

bool __fastcall StringToDateTime(const UTF8String &Str, TDateTime &DateTime)
{
   if ( Str.Length() != 8 + 6 )
   {
      return false;
   }

   unsigned short Year, Month, Day;
   unsigned short Hour, Min, Sec;

   Year = StrToInt(Str.SubString(1, 4).c_str());
   Month = StrToInt(Str.SubString(1 + 4, 2).c_str());
   Day = StrToInt(Str.SubString(1 + 4 + 2, 2).c_str());
   Hour = StrToInt(Str.SubString(1 + 4 + 2 + 2, 2).c_str());
   Min = StrToInt(Str.SubString(1 + 4 + 2 + 2 + 2, 2).c_str());
   Sec = StrToInt(Str.SubString(1 + 4 + 2 + 2 + 2 + 2, 2).c_str());

   try
   {
      DateTime = TDateTime(Year, Month, Day) + TDateTime(Hour, Min, Sec, 0);
   }
   catch ( EConvertError &e )
   {
      return false;
   }

   return true;
}

int __fastcall SubDateTime(const TDateTime &DateTime1, const TDateTime &DateTime2)
{
   TDateTime DateTime = DateTime1 - DateTime2;
   unsigned short Day;
   unsigned short Hour;
   unsigned short Min;
   unsigned short Sec;
   unsigned short MSec;

   if ( DateTime >= TDateTime(1) )
   {
      Day = 1;
      DateTime -= TDateTime(1);
   }
   else
   {
      Day = 0;
   }

   DateTime.DecodeTime(&Hour, &Min, &Sec, &MSec);
   return Day * 24 * 3600 + Hour * 3600 + Min * 60 + Sec;
}

UTF8String __fastcall DateTimeToString1(const TDateTime &DateTime)
{
   char TmpStr[200 + 1];
   unsigned short Year;
   unsigned short Month;
   unsigned short Day;
   unsigned short Hour;
   unsigned short Min;
   unsigned short Sec;
   unsigned short MSec;

   DateTime.DecodeDate(&Year, &Month, &Day);
   DateTime.DecodeTime(&Hour, &Min, &Sec, &MSec);
   snprintf(TmpStr, 200, "%02d:%02d", Hour, Min);

   return UTF8String(TmpStr);
}

UTF8String __fastcall DateTimeToString2(const TDateTime &DateTime)
{
   char TmpStr[200 + 1];
   unsigned short Year;
   unsigned short Month;
   unsigned short Day;
   unsigned short Hour;
   unsigned short Min;
   unsigned short Sec;
   unsigned short MSec;

   DateTime.DecodeDate(&Year, &Month, &Day);
   DateTime.DecodeTime(&Hour, &Min, &Sec, &MSec);
   snprintf(TmpStr, 200, "%02d-%02d %02d:%02d", Month, Day, Hour, Min);

   return UTF8String(TmpStr);
}

UTF8String __fastcall DateTimeToString3(const TDateTime &DateTime)
{
   char TmpStr[200 + 1];
   unsigned short Year;
   unsigned short Month;
   unsigned short Day;
   unsigned short Hour;
   unsigned short Min;
   unsigned short Sec;
   unsigned short MSec;

   DateTime.DecodeDate(&Year, &Month, &Day);
   DateTime.DecodeTime(&Hour, &Min, &Sec, &MSec);
   snprintf(TmpStr, 200, "%02d:%02d:%02d", Hour, Min, Sec);

   return UTF8String(TmpStr);
}

#pragma package(smart_init)
